package org.bot.server.socket.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.bot.client.driver.api.server.ServerUpdateClientStatus;
import org.bot.client.driver.api.server.ServerReceiveClientData;
import org.bot.server.client.service.BotClientSocketDriveService;
import org.bot.server.job.FlowQuartzJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 沧月
 * @create 0022 2023/9/22 11:36
 * @description <WebSocket 服务端代码>
 */
@Component
public class ServerWebSocket extends TextWebSocketHandler {

    public Map<String, WebSocketSession> clientSession = new HashMap<>();
    public Map<String, String> sessionIdMappingClient = new HashMap<>();

    @Autowired
    ServerReceiveClientData botFlowService;

    @Autowired
    ServerUpdateClientStatus clientStatus;

    @Autowired
    BotClientSocketDriveService botClientService;

    @Autowired
    FlowQuartzJob quartzJob;


    public WebSocketSession getSession(String key) {
        return clientSession.get(key);
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws IOException {
        ServerClientAuth serverClientAuth = new ServerClientAuth(session, this);
        String clientId = serverClientAuth.auth(botClientService);
        if (clientId == null) {
            this.closeClient(session, AuthMessage.CODE_4309);
        }

        if (clientSession.containsKey(clientId)) {
            this.sendMessage(getMessage(MessageType.HEARTBEAT), clientId);
            this.closeClient(session, AuthMessage.CODE_4309);
        }

        clientSession.put(clientId, session);
        sessionIdMappingClient.put(session.getId(), clientId);
        clientStatus.clientOnline(clientId);
        quartzJob.addClientJob(clientId);

        //发送连接成功消息
        this.sendMessage(getMessage(MessageType.CONNECT), clientId);

        //发送拉取Event消息
        this.sendMessage(getMessage(MessageType.EVENT), clientId);
    }

    public void closeClient(WebSocketSession session, AuthMessage authMessage) throws IOException {
        session.close(new CloseStatus(authMessage.code, authMessage.message));
        throw new RuntimeException(authMessage.message);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        String clientId = sessionIdMappingClient.get(session.getId());
        if (clientId == null) {
            return;
        }
        sessionIdMappingClient.remove(session.getId());
        clientSession.remove(clientId);
        clientStatus.clientOffline(clientId);
        quartzJob.deleteClientJob(clientId);
    }

    @Override
    public void handleMessage(WebSocketSession wsSession, WebSocketMessage<?> message) throws IOException {
        String dataStr = message.getPayload().toString();
        JSONObject socketData = JSONObject.parseObject(dataStr);
        Object data = socketData.get("data");
        String clientId = sessionIdMappingClient.get(wsSession.getId());
        switch (socketData.getString("msgType")) {
            case "log":
                botFlowService.clientLog((JSONObject) data);
                break;
            case "event":
                botFlowService.clientEvent(clientId, (JSONArray) data);
                break;
            case "logInfo":
                botFlowService.clientExecLog((JSONObject) data);
                break;
            case "heartbeat":
                break;
            case "status":
                botFlowService.clientStatus(clientId,(JSONObject) data);
                break;
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("WebSocket服务端异常");
    }

    public boolean sendMessage(String msg, WebSocketSession webSocketSession) {
        try {
            webSocketSession.sendMessage(new TextMessage(msg));
        } catch (IOException e) {
            e.printStackTrace();
            String id = webSocketSession.getId();
            this.clientSession.remove(id);
            String clientId = this.sessionIdMappingClient.remove(id);
            clientStatus.clientOffline(clientId);
            try {
                webSocketSession.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }
        return true;
    }

    public boolean sendMessage(Object msg, String clientId) {
        return this.sendMessage(msg.toString(), this.getSession(clientId));
    }

    public JSONObject getMessage(MessageType type) {
        return new JSONObject().fluentPut("type", type.getType());
    }

}
